/*
 * Ormbr.cs
 * 
 * Copyright (c) 2003-2004, dnAnalytics Project. All rights reserved.
*/

#if !MANAGED
using System;
using System.Runtime.InteropServices;

using dnA.Utility;

namespace dnA.Math.Lapack{
	[System.Security.SuppressUnmanagedCodeSecurityAttribute]
	internal sealed class Ormbr {
		private  Ormbr() {}                           
		private static void ArgumentCheck(Vector vect, Side side, int m, int n, int k, Object A, int lda, Object tau, Object C, int ldc) {
			if ( A == null ) {
				throw new ArgumentNullException("A","A cannot be null.");
			}
			if ( tau == null ) {
				throw new ArgumentNullException("tau","tau cannot be null.");
			}
			if ( C == null ) {
				throw new ArgumentNullException("C","C cannot be null.");
			}
			if ( m<0 ) {
				throw new ArgumentException("m must be at least zero.");
			}
			if ( n<0 ) {
				throw new ArgumentException("n must be at least zero.");
			}
			if( k < 0 ){
				throw new ArgumentException("k must be at least zero..");
			}

			if( vect == Vector.Q ){
				if( side == Side.Left){
					if ( lda < System.Math.Max(1,m) ) {
						throw new ArgumentException("lda must be at least max(1,m)");
					}				
				}else{
					if ( lda < System.Math.Max(1,n) ) {
						throw new ArgumentException("lda must be at least max(1,n)");
					}				
				}
			}else{
				if( side == Side.Left){
					if ( lda < System.Math.Max(1,System.Math.Min(m,k))) {
						throw new ArgumentException("lda must be at least max(1,min(m,k))");
					}
				}else{
					if ( lda < System.Math.Max(1,System.Math.Min(n,k))) {
						throw new ArgumentException("lda must be at least max(1,min(n,k))");
					}
				}
			}
		
			if ( ldc < System.Math.Max(1,m)) {
				throw new ArgumentException("ldc must be at least max(1,m)");
			}	
		}
		
		internal static int Compute( Vector vect, Side side, Transpose trans, int m, int n, int k, float[] A, int lda, float[] tau, float[] C, int ldc ){
			ArgumentCheck(vect,side, m, n, k, A, lda, tau, C, ldc);
			if( side == Side.Left){
				if (tau.Length < System.Math.Max(1, System.Math.Min(m,k))){
					throw new ArgumentException("tau must be at least max(1,k).");
				}
			}else{
				if (tau.Length < System.Math.Max(1, System.Math.Min(n,k))){
					throw new ArgumentException("tau must be at least max(1,k).");
				}
			}
			
			
			return dna_lapack_sormbr(Configuration.BlockSize, vect, side, trans, m, n, k, A, lda, tau, C, ldc);
		}

		internal static int Compute( Vector vect, Side side, Transpose trans, int m, int n, int k, double[] A, int lda, double[] tau, double[] C, int ldc ){
			ArgumentCheck(vect,side, m, n, k, A, lda, tau, C, ldc);
			if( side == Side.Left){
				if (tau.Length < System.Math.Max(1, System.Math.Min(m,k))){
					throw new ArgumentException("tau must be at least max(1,k).");
				}
			}else{
				if (tau.Length < System.Math.Max(1, System.Math.Min(n,k))){
					throw new ArgumentException("tau must be at least max(1,k).");
				}
			}
			
			
			return dna_lapack_dormbr(Configuration.BlockSize, vect, side, trans, m, n, k, A, lda, tau, C, ldc);
		}

		[DllImport(dnA.Utility.Configuration.BLASLibrary, ExactSpelling=true, SetLastError=false)]
		private static extern int dna_lapack_sormbr( int block_size, Vector vect, Side side, Transpose trans, int m, int n, int k, [In,Out]float[] A, int lda, [In,Out]float[] tau, [In,Out]float[] C, int ldc  );
	
		[DllImport(dnA.Utility.Configuration.BLASLibrary, ExactSpelling=true, SetLastError=false)]
		private static extern int dna_lapack_dormbr( int block_size, Vector vect, Side side, Transpose trans, int m, int n, int k, [In,Out]double[] A, int lda, [In,Out]double[] tau, [In,Out]double[] C, int ldc   );
	}
}
#endif